package services.dingtalk

import models.users._

import javax.inject.{Inject, Singleton}
import play.api.Logging

import java.time.LocalDateTime
import scala.collection.mutable
import scala.concurrent.ExecutionContext

@Singleton
class ContentUpdateService @Inject()(dingtalkService: DingtalkService,
                                     usersRepo: UserGroupRepository
                                    )(implicit exec: ExecutionContext) extends Logging {
  val encode = security.Encode

  /**
   *
   * @param company
   * @return
   */
  def getUsersInfo(company: String) = {
      val com = DingtalkService.companyNum(company)
      val deps = dingtalkService.getPartment(company)
      val userids = mutable.Set[(Int, String)]()
      val groupUsers = mutable.Set[(Int, String, String)]()
      val depsIterator = deps.get.iterator()
      while (depsIterator.hasNext) {
        val dep = depsIterator.next()
        dingtalkService.groupCreate(Group(id = dep.getId, parentid = dep.getParentid, pname = dep.getName, company = com))
        //          println(dep.getId)
        val members = dingtalkService.getDeptMember(company, dep.getId.toString)
        val users = members.getUserIds.iterator()
        while (users.hasNext) {
          val user = users.next()
          userids.add((com, user))
          groupUsers.add((com, dep.getId.toString, user))
        }
      }
      (userids, groupUsers)
  }

  /**
   * @param allUpdate
   * @return
   */
  def updateDingtalkUsers(company: String, allUpdate: Boolean = false) = {
    val companyNum = DingtalkService.companyNum(company)
    val updateUsers = this.getUsersInfo(company)
    logger.debug(s"get users form dingtalk:\nuserids Set:${updateUsers._1.mkString(",")}\ngroupUsers Set:${updateUsers._2.mkString(",")}")
    //      try {
    val userSet = updateUsers._1
    val comgroupuserSet = updateUsers._2
    usersRepo.getUserInfoSimple(companyNum).map { dbAllUsers =>
      val dbAlluserId = dbAllUsers.map(u => u._2 + "@" + u._1).toSet
      val dtAlluserid = userSet.map(u => u._2 + "@" + u._1).toSet
      val dbUseridIsActive = dbAllUsers.filter(f => f._3 >= 1 && f._1 == companyNum).map(u => u._2 + "@" + u._1).toSet
      val userIsPublic = dtAlluserid & dbUseridIsActive
      val userOnlyDt = dtAlluserid &~ userIsPublic
      val userOnlyDb = dbUseridIsActive &~ userIsPublic
      //create or update user
      val userforeach = if (allUpdate) {
        usersRepo.accountSetPermission()
        dtAlluserid
      }
      else userOnlyDt
      userforeach.foreach(u => dingtalkService.getUser(company, u.split("@")(0)))
      logger.debug(s"updateDingtalkUsers====>\n " +
        s"dbAlluserId:${dbAlluserId.toArray.length}\n," +
        s"dtAlluserid:${dtAlluserid.toArray.length}\n," +
        s"dbUseridIsActive:${dbUseridIsActive.toArray.length}\n," +
        s"userIsPublic:${userIsPublic.toArray.length}\n," +
        s"userOnlyDt:${userOnlyDt.toArray.length}\n," +
        s"userOnlyDb:${userOnlyDb.toArray.length}")
      userOnlyDb.foreach {
        uid => {
          val userid = uid.split("@")(0)
          //          val com = dbAllUsers.filter(f => f._2 == userid).map(a => a._1).head
          val activeValue = dbAllUsers.filter(f => f._2 == userid).map(a => a._3).head
          logger.debug(s"userOnlyDb is update false:${userid},$companyNum,$activeValue")
          usersRepo.userActiveFalse(companyNum, userid, activeValue)
        }
      }
      userIsPublic.foreach {
        uid => {
          val userid = uid.split("@")(0)
          //          val com = dbAllUsers.filter(f => f._2 == userid).map(a => a._1).head
          val activeValue = dbAllUsers.filter(f => f._2 == userid).map(a => a._3).head
          if (activeValue < 5) {
            usersRepo.userInfoActive(company = companyNum, userid = userid)
          }
        }
      }
      logger.debug(s"${LocalDateTime.now.toString},compang:$company,userOnlyDt:${userOnlyDt.toString},userOnlyDb:${userOnlyDb.toString}")
      (userOnlyDt.size, userOnlyDb.size)
    }.map { resUser =>
      // group
      val ugUpSet = mutable.Set[String]() // group_user_com
      for {accAll <- usersRepo.getUserInfoSimple(companyNum)
           cgu <- comgroupuserSet
           } {
        accAll.filter(f => f._2 == cgu._3 && f._1 == cgu._1).map(_._5).map {
          uid => ugUpSet.add(s"${cgu._2}_${uid.get}"); ugUpSet
        }
      }.map {
        ugDt =>
          usersRepo.ugRelationFind.map { fu =>
            val groupUsers = fu.map(f => s"${f.gid}_${f.uid}").toSet
            val pUG = groupUsers & ugDt
            val deleteUG = groupUsers &~ pUG
            val insertUG = ugDt &~ pUG
            deleteUG.foreach(d => {
              val ug = d.split("_")
              usersRepo.ugRelationDelete(gid = Some(ug(0).toLong), uid = Some(ug(1).toInt))
            })
            insertUG.foreach(d => {
              val ug = d.split("_")
              val uid = ug(1).toInt
              val gid = ug(0).toLong
              val id = encode.hashFNV1a64(d)
              val userGroup = UserGroup(id = id, uid = uid, gid = gid)
              //              logger.debug(userGroup.toString)
              usersRepo.ugRelationCreate(userGroup)
            })
          }
      }
      s"users:${userSet.size},c:${resUser._1},d:${resUser._2}."
    }
  }


}
